package cdu.sl.service.impl;

import cdu.sl.custom.CustomUserDetails;
import cdu.sl.pojo.dto.StudentScoreInfoDTO;
import cdu.sl.pojo.dto.SubmitScoreInfoDTO;
import cdu.sl.pojo.entity.manage.ReportOrganization;
import cdu.sl.pojo.entity.manage.Role;
import cdu.sl.pojo.entity.manage.User;
import cdu.sl.pojo.entity.service.TestAssessmentSummary;
import cdu.sl.pojo.entity.service.TestItem;
import cdu.sl.pojo.entity.service.TestItemScore;
import cdu.sl.pojo.entity.service.WeightConfig;
import cdu.sl.pojo.vo.DashBoardVO;
import cdu.sl.pojo.vo.PhysicalTestDataReportWorkDetailsVO;
import cdu.sl.pojo.vo.TestItemScoreInfoVO;
import cdu.sl.pojo.vo.TestItemVO;
import cdu.sl.repository.basic.StudentRepository;
import cdu.sl.repository.manage.ReportOrganizationRepository;
import cdu.sl.repository.service.TestAssessmentSummaryRepository;
import cdu.sl.repository.service.TestItemRepository;
import cdu.sl.repository.service.TestItemScoreRepository;
import cdu.sl.repository.service.WeightConfigRepository;
import cdu.sl.service.DataReportService;
import com.fasterxml.jackson.core.JsonProcessingException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;

@Slf4j
@Service
@RequiredArgsConstructor
public class DataReportServiceImpl implements DataReportService {

    private final ReportOrganizationRepository reportOrganizationRepository;

    private final StudentRepository studentRepository;

    private final TestAssessmentSummaryRepository assessmentSummaryRepository;

    private final TestItemRepository testItemRepository;

    private final TestItemScoreRepository testItemScoreRepository;

    private final WeightConfigRepository weightConfigRepository;

    /**
     * 查询本年度体测工作安排
     */
    @Override
    public PhysicalTestDataReportWorkDetailsVO getThisYearWorkDetails() {
        Integer currentYear = LocalDate.now().getYear();
        // 根据年份数据查询表中是否有对应的安排
        ReportOrganization thisYearReportOrganization = reportOrganizationRepository.findByYear(currentYear);
        PhysicalTestDataReportWorkDetailsVO vo = new PhysicalTestDataReportWorkDetailsVO();
        if (thisYearReportOrganization != null) {
            BeanUtils.copyProperties(thisYearReportOrganization, vo);
            vo.setIsStart(true);  // 有记录 ，说明本年度体测数据进行中
            LocalDateTime now = LocalDateTime.now();
            if (now.isBefore(thisYearReportOrganization.getBeginDate())) {
                vo.setStatus(0); // 当前日期在开始日期之前 说明未开始
            } else if (now.isAfter(thisYearReportOrganization.getEndDate())) {
                vo.setStatus(2); // 当前日期在开始日期之后 说明已结束
            } else {
                vo.setStatus(1);
            }
            log.info("查询到今年体测工作安排：{}", thisYearReportOrganization);
            return vo;
        }
        log.info("未查询到本年度体测工作安排,工作尚未开展");
        return null;
    }

    /**
     * 获取数据仪表盘的必要数据
     */
    @Override
    public DashBoardVO getDashBoardRequiredDataByRole() throws JsonProcessingException {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

        CustomUserDetails customUserDetails = (CustomUserDetails) authentication.getPrincipal();
        return doGetDashBoardRequiredDataByRole(customUserDetails.getUser());
    }

    /**
     * 根据学生id获取体测条目
     *
     * @param studentId 学生id
     * @return 体测条目清单
     */
    @Override
    public List<TestItemVO> getTestItemsByStudentId(Long studentId) {
        List<TestItem> testItems = testItemRepository.findTestItemsByStudentId(studentId);
        return testItems.stream().map(testItem -> {
            TestItemVO vo = new TestItemVO();
            BeanUtils.copyProperties(testItem, vo);
            return vo;
        }).toList();
    }

    /**
     * 录入学生成绩
     *
     * @param studentId    学生id
     * @param scoreInfoDTO 成绩信息
     */
    @Override
    @Transactional
    public void submitScoreInfo(Long studentId, SubmitScoreInfoDTO scoreInfoDTO) {
        Integer currentYear = LocalDateTime.now().getYear();
        Long gradeId = studentRepository.findGradeIdByStudentId(studentId);
        // todo
        AtomicReference<Float> totalScore = new AtomicReference<>(0.0F);

        // 首先将各单项成绩录入到tb_test_item_score
        scoreInfoDTO.getScoreInfo().forEach(singleItemInfo -> {
            TestItemScore testItemScore = new TestItemScore();
            BeanUtils.copyProperties(singleItemInfo, testItemScore);
            testItemScore.setStudentId(studentId);
            testItemScore.setTestYear(currentYear);
            testItemScore.setTestDate(LocalDateTime.now());
            testItemScore.setIsValid(true);
            // 根据年级id和测试条目id查询到权重
            log.info("查询权重配置条件：{},{},{}", gradeId, singleItemInfo.getItemId(), currentYear);
            Optional<WeightConfig> opt = weightConfigRepository.findByGradeIdAndItemIdAndTestYear(gradeId, singleItemInfo.getItemId(), currentYear);
            if (opt.isPresent()) {
                float realSingleScore = opt.get().getWeight() * singleItemInfo.getScore();
                Optional<TestItem> itemInfo = testItemRepository.findById(opt.get().getItemId());
                log.info("{}:单项得分：{}", itemInfo.get().getName(), realSingleScore);
                Optional<TestItem> itemOpt = testItemRepository.findById(opt.get().getId());
                totalScore.updateAndGet(v -> v + realSingleScore);
            }

            testItemScoreRepository.save(testItemScore);
        });

        // 每个测试项记录完毕之后 ，再将成绩记录到总评表
        TestAssessmentSummary testAssessmentSummary = new TestAssessmentSummary();
        testAssessmentSummary.setStudentId(studentId);
        testAssessmentSummary.setTestYear(currentYear);
        testAssessmentSummary.setTotalScore(totalScore.get());
        testAssessmentSummary.setGrade(judgeGrade(totalScore.get()));
        assessmentSummaryRepository.save(testAssessmentSummary);
    }


    /**
     * 根据学生id查询成绩信息
     *
     * @param studentId 学生id
     * @return 测试条目VO对象
     */
    @Override
    public List<TestItemScoreInfoVO> getStudentScoreInfoById(Long studentId) {
        return testItemScoreRepository.findTestItemScoresByStudentId(studentId);

    }

    /**
     * 修改学生成绩信息业务逻辑
     *
     * @param studentId           学生id
     * @param studentScoreInfoDTO 修改信息
     */
    @Override
    @Transactional
    public void updateStudentScoreInfo(Long studentId, StudentScoreInfoDTO studentScoreInfoDTO) {
        Long gradeId = studentRepository.findGradeIdByStudentId(studentId);
        Integer currentYear = LocalDateTime.now().getYear();
        AtomicReference<Float> totalScore = new AtomicReference<>(0.0F);
        // 遍历保存学生成绩信息
        studentScoreInfoDTO.getScoreInfoDTOS().forEach(singleItemScoreInfoDTO -> {
            TestItemScore newTestItemScore = new TestItemScore();
            BeanUtils.copyProperties(singleItemScoreInfoDTO, newTestItemScore);
            newTestItemScore.setStudentId(studentId);
            Optional<TestItemScore> opt = testItemScoreRepository.findById(newTestItemScore.getId());
            opt.ifPresent(testItemScore -> {
                testItemScore.setScore(newTestItemScore.getScore());
                testItemScore.setGrade(newTestItemScore.getGrade());
                // 更新总评成绩表
                Optional<WeightConfig> weightOpt = weightConfigRepository.findByGradeIdAndItemIdAndTestYear(gradeId, testItemScore.getItemId(), currentYear);
                if (weightOpt.isPresent()) {
                    float realSingleScore = weightOpt.get().getWeight() * singleItemScoreInfoDTO.getScore();  // 由单项得分乘以权重得到真实得分
                    totalScore.updateAndGet(v->v+realSingleScore);
                    // 查询此学生对应总分记录表中的记录
                    TestAssessmentSummary studentScoreRecord = assessmentSummaryRepository.findByStudentIdAndTestYear(studentId, currentYear);
                    studentScoreRecord.setTotalScore(totalScore.get());  // 更新总分
                    assessmentSummaryRepository.save(studentScoreRecord); // 保存更新后的分数数据
                }

                log.info("修改学生单项成绩信息：testItemScore:{}", testItemScore);
                testItemScoreRepository.save(testItemScore);
            });
        });
        log.info("修改学生：{}体测成绩成功", studentId);
    }


    // 根据得分评等级
    private Integer judgeGrade(Float score) {
        if (score >= 90.0) {
            return 0;
        } else if (score >= 80) {
            return 1;
        } else if (score >= 60) {
            return 2;
        } else {
            return 3;
        }
    }


    private DashBoardVO doGetDashBoardRequiredDataByRole(User user) {
        List<Role> roles = user.getRoles();
        Role role = roles.get(0);
        Long schoolId = user.getSchoolId();
        Long classId = user.getClassId();
        if (role.getName().equals("EDU_BUR_ADMINISTRATOR")) {
            return eduAdminDashBoardData();
        } else if (role.getName().equals("SCHOOL_ADMINISTRATOR")) {
            return schoolAdminDashBoardData(schoolId);
        } else {
            return headTeacherDashBoardData(classId);
        }

    }

    /**
     * 角色为教育局管理员时获取的数据
     *
     * @return DashBoard视图模型
     */
    public DashBoardVO eduAdminDashBoardData() {
        log.info("教育局管理员获得dashboard数据");
        DashBoardVO dashBoardVO = new DashBoardVO();
        dashBoardVO.setRole(2);
        // 教育局管理员需要获取的数据
        // 查询全市学生的上报情况
        // 查询学生表的总人数
        long studentCount = studentRepository.count();
        // 查询本年度已经上报数据的学生数量
        int currentYear = LocalDateTime.now().getYear();
        Long finishedCount = assessmentSummaryRepository.countByTestYear(currentYear);
        dashBoardVO.setFinishedCount(finishedCount.intValue());
        dashBoardVO.setUnfinishedCount((int) studentCount - finishedCount.intValue());
        // 查询全市近五年的及格率分布
        int startYear = currentYear - 4; // 近五年，从 2021 开始
        // 根据 schoolId 选择查询方法
        List<Object[]> results = assessmentSummaryRepository.findPassRateByYearRange(startYear, currentYear);

        // 初始化结果 Map
        Map<Integer, Float> qualifiedRateMap = new HashMap<>();
        for (int year = startYear; year <= currentYear; year++) {
            qualifiedRateMap.put(year, 0.0f); // 默认值为 0.0
        }

        // 填充查询结果
        for (Object[] result : results) {
            // 检查结果类型并进行安全转换
            Object yearObj = result[0];
            Object passRateObj = result[1];

            Integer year;
            if (yearObj instanceof Integer) {
                year = (Integer) yearObj;
            } else if (yearObj instanceof java.sql.Date) {
                year = ((java.sql.Date) yearObj).toLocalDate().getYear();
            } else {
                year = Integer.valueOf(yearObj.toString());
            }

            Float passRate;
            if (passRateObj instanceof Number) {
                passRate = ((Number) passRateObj).floatValue();
            } else {
                passRate = Float.valueOf(passRateObj.toString());
            }

            qualifiedRateMap.put(year, passRate);
        }

        dashBoardVO.setRecentFiveYearsQualifiedRate(qualifiedRateMap);

        // 获取本年度各个成绩段的学生人数并填充到DashBoardVO中
        dashBoardVO.setExcellence(assessmentSummaryRepository.countExcellentStudentsByCityAndYear(currentYear).intValue());// 优秀
        dashBoardVO.setGood(assessmentSummaryRepository.countGoodStudentsByCityAndYear(currentYear).intValue());   // 良好
        dashBoardVO.setQualified(assessmentSummaryRepository.countPassingStudentsByCityAndYear(currentYear).intValue());  // 合格
        dashBoardVO.setSubstandard(assessmentSummaryRepository.countFailingStudentsByCityAndYear(currentYear).intValue());  // 不合格

        return dashBoardVO;
    }


    /**
     * 校级管理员获取的DashBoard数据
     *
     * @return DashBoardVO
     */
    public DashBoardVO schoolAdminDashBoardData(Long schoolId) {
        log.info("校级管理员获取首页dashboard数据");
        DashBoardVO dashBoardVO = new DashBoardVO();
        dashBoardVO.setRole(1);
        // 教育局管理员需要获取的数据
        // 查询全市学生的上报情况
        // 查询本校的总人数
        long studentCount = studentRepository.countBySchoolId(schoolId);
        // 查询本年度已经上报数据的学生数量
        int currentYear = LocalDateTime.now().getYear();
        Long finishedCount = assessmentSummaryRepository.countStudentsWithTestsBySchoolIdAndYear(currentYear, schoolId);
        dashBoardVO.setFinishedCount(finishedCount.intValue());
        dashBoardVO.setUnfinishedCount((int) studentCount - finishedCount.intValue());
        // 查询全市近五年的及格率分布
        int startYear = currentYear - 4; // 近五年，从 2021 开始
        // 根据 schoolId 选择查询方法
        List<Object[]> results = assessmentSummaryRepository.findPassRateByYearRangeAndSchoolId(startYear, currentYear, schoolId);

        // 初始化结果 Map
        Map<Integer, Float> qualifiedRateMap = new HashMap<>();
        for (int year = startYear; year <= currentYear; year++) {
            qualifiedRateMap.put(year, 0.0f); // 默认值为 0.0
        }

        // 填充查询结果
        for (Object[] result : results) {
            // 检查结果类型并进行安全转换
            Object yearObj = result[0];
            Object passRateObj = result[1];

            Integer year;
            if (yearObj instanceof Integer) {
                year = (Integer) yearObj;
            } else if (yearObj instanceof java.sql.Date) {
                year = ((java.sql.Date) yearObj).toLocalDate().getYear();
            } else {
                year = Integer.valueOf(yearObj.toString());
            }

            Float passRate;
            if (passRateObj instanceof Number) {
                passRate = ((Number) passRateObj).floatValue();
            } else {
                passRate = Float.valueOf(passRateObj.toString());
            }

            qualifiedRateMap.put(year, passRate);
        }

        // 获取本校本年度各分段的成绩状况
        dashBoardVO.setExcellence(assessmentSummaryRepository.countExcellentStudentsBySchoolAndYear(schoolId, currentYear).intValue());
        dashBoardVO.setGood(assessmentSummaryRepository.countGoodStudentsBySchoolAndYear(schoolId, currentYear).intValue());
        dashBoardVO.setQualified(assessmentSummaryRepository.countPassingStudentsBySchoolAndYear(schoolId, currentYear).intValue());
        dashBoardVO.setSubstandard(assessmentSummaryRepository.countFailingStudentsBySchoolAndYear(schoolId, currentYear).intValue());

        dashBoardVO.setRecentFiveYearsQualifiedRate(qualifiedRateMap);
        return dashBoardVO;
    }


    /**
     * 统计班主任的数据看板所需数据
     *
     * @param classId 班级id
     * @return
     */
    public DashBoardVO headTeacherDashBoardData(Long classId) {
        log.info("班级管理员获取dashboard数据");
        DashBoardVO dashBoardVO = new DashBoardVO();
        dashBoardVO.setRole(0);
        int thisYear = LocalDateTime.now().getYear();
        // 统计本班学生数据上报情况
        // 统计班级总人数
        long studentCount = studentRepository.countByClassId(classId);
        // 已经完成数据上报的学生个数
        long finishedCount = assessmentSummaryRepository.countStudentsWithTestsByClassIdAndYear(thisYear, classId);
        dashBoardVO.setFinishedCount((int) finishedCount);
        dashBoardVO.setUnfinishedCount((int) studentCount - (int) finishedCount);

        // 近五年的合格率数据（班级模式下可以不需要，但为保持一致性添加空Map）
        int startYear = thisYear - 4;
        Map<Integer, Float> qualifiedRateMap = new HashMap<>();
        for (int year = startYear; year <= thisYear; year++) {
            qualifiedRateMap.put(year, 0.0f); // 默认值为 0.0
        }
        dashBoardVO.setRecentFiveYearsQualifiedRate(qualifiedRateMap);

        // 获取本班级本年度各个成绩段的学生人数
        dashBoardVO.setExcellence(assessmentSummaryRepository.countExcellentStudentsByClassAndYear(classId, thisYear).intValue());
        dashBoardVO.setGood(assessmentSummaryRepository.countGoodStudentsByClassAndYear(classId, thisYear).intValue());
        dashBoardVO.setQualified(assessmentSummaryRepository.countPassingStudentsByClassAndYear(classId, thisYear).intValue());
        dashBoardVO.setSubstandard(assessmentSummaryRepository.countFailingStudentsByClassAndYear(classId, thisYear).intValue());

        return dashBoardVO;
    }


}
